home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
4_0
/
VIVIDUS
/
QD3D.SIT
/
qd3d
/
qd3dLib.c
< prev
Wrap
C/C++ Source or Header
|
1991-10-05
|
18KB
|
862 lines
#include <Cqd3dPort.h>
#include <gouraud.h>
#include <SANE.h>
extern Cqd3dPort *the3dPort;
/* ======================================================================
Cqd3dPort primitive three dimensional drawing routine library.
This is part of the qd3d Vividus Source Code Library. See the
extern qd3d.doc documentation file for usage. See individual
routines for routine documentation.
Copyright 1991 by Vividus Consulting.
This is not public domain source code. You may not copy and
paste from this source code. Read your Vividus Licensing
agreement for details and other restrictions.
====================================================================== */
static FixedVector fdc[PolyMaxN];
static FixedVector cfdc[PolyMaxN];
static vector eyec[PolyMaxN];
static vector ceyec[PolyMaxN];
static vector ndc[PolyMaxN];
static vector cndc[PolyMaxN];
static vector tcolor[PolyMaxN];
static vector ccolor[PolyMaxN];
static FixedVector frgb[PolyMaxN];
static FixedVector cfrgb[PolyMaxN];
/* ============================================================ */
/* Color primitives: */
void
Color2RGB(vector *c, RGBColor *rgb)
/*
This converts the color vector c to the equivalent RGBColor in rgb.
*/
{
FixedVector tc;
GetFColor(c, &tc);
cv2rgb(&tc, rgb);
}
void
RGB2Color(RGBColor *rgb, vector *c)
/*
This converts the RGBColor in rgb to the equivalent color vector c.
*/
{
FixedVector tc;
c->x = rgb->red/65535.0;
c->y = rgb->green/65535.0;
c->z = rgb->blue/65535.0;
}
void
vForeColor(vector *c)
/*
Set the foreground color to that indicated by c.
*/
{
RGBColor rgb;
Color2RGB(c, &rgb);
RGBForeColor(&rgb);
}
void
GetFColor(vector *c, FixedVector *fc)
/*
Given the color c, this returns the equivalent fixed point
representation in fc.
Warning: This is a private function to the qd3d library and is
highly subject to change or removal.
*/
{
#if 0
if ((c->x > 1.0) || (c->y > 1.0) || (c->z > 1.0))
Debugger();
if ((c->x < 0.0) || (c->y < 0.0) || (c->z < 0.0))
Debugger();
#endif
fc->x = ((long)(65535.0 * c->x)) << 15;
fc->y = ((long)(65535.0 * c->y)) << 15;
fc->z = ((long)(65535.0 * c->z)) << 15;
}
void
cv2rgb(FixedVector *f, RGBColor *rgb)
/*
Given the fixed point color in f, this returns the appropriate
RGBColor in rgb.
Warning: This is a private function to the qd3d library and is
highly subject to change or removal.
*/
{
rgb->red = HiWord(f->x << 1);
rgb->green = HiWord(f->y << 1);
rgb->blue = HiWord(f->z << 1);
}
void
rgb2cv(RGBColor *rgb, FixedVector *f)
/*
Given the RGBColor rgb, this returns the equivalent fixed point
representation in f.
Warning: This is a private function to the qd3d library and is
highly subject to change or removal.
*/
{
f->x = (long)(rgb->red) << 15;
f->y = (long)(rgb->green) << 15;
f->z = (long)(rgb->blue) << 15;
}
static void
LoadFColors(int n, vector color[]) {
/*
Note: that cfdc must be set up BEFORE calling this routine.
Warning: This is a private function to the qd3d library and is
highly subject to change or removal.
*/
int i;
for (i = 0; i < n; i++) {
GetFColor(&color[i], &cfrgb[i]);
if (the3dPort->usedepthque) {
DepthColor(&cfrgb[i], cfdc[i].z, &cfrgb[i]);
}
}
return;
/* The following notice may not be removed under any
circumstance. See your licensing agreement. */
asm {
dc.b "qd3dLib Copyright 1991 Vividus Consulting"
}
}
/* ------------------------------------------------------------ */
/* The following should be considered private to the qd3d library. */
static struct {
int size;
Rect bbox;
Point points[PolyMaxN];
} mypoly;
static PolyPtr polyptr = (PolyPtr)&mypoly;
/*
The following defines have obvious and intended side affects. Ie.
They aren't just functions.
*/
#define MAXA(a,b) {if ( b > a) a = b;}
#define MINA(a,b) {if ( b < a) a = b;}
static PolyForm(int n, FixedVector fx[])
/*
This routine sets mypoly to reflect the polygon defined by n and fx.
This is a quicker way of making a quickdraw polygon than OpenPoly.
*/
{
int i = 0;
IntVector p;
mypoly.size = 10 + (n + 1) * sizeof(Point);
fv2iv(&fx[i], &p);
mypoly.bbox.top = p.y;
mypoly.bbox.left = p.x;
mypoly.bbox.right = p.x;
mypoly.bbox.bottom = p.y;
for (i = 0; i < n; i++) {
fv2iv(&fx[i], &p);
mypoly.points[i].h = p.x;
mypoly.points[i].v = p.y;
MINA(mypoly.bbox.top, p.y);
MINA(mypoly.bbox.left, p.x);
MAXA(mypoly.bbox.right, p.x);
MAXA(mypoly.bbox.bottom, p.y);
}
mypoly.points[n].h = mypoly.points[0].h;
mypoly.points[n].v = mypoly.points[0].v;
}
/* ============================================================ */
/* Drawing primitives: */
int
Qd3dError(void)
/*
This returns the most recently occured qd3d error of the current
3d port.
Note: this routine is what clears the last reported error
instead of the individual routines!
*/
{
return(the3dPort->Qd3dError());
}
void
MoveTo3d(vector *x)
/*
Move to the position x without drawing.
This routine will also reposition the 2d pen -- useful for
positioning text. With this application, be sure and check
Qd3dError to see if the pen has been positioned outside
the current view volume.
*/
{
FixedVector p;
int n = 1;
vcopy(x, &the3dPort->position);
TranClipProjf(&n, &the3dPort->position, &p);
MoveTo(HiWord(p.x), HiWord(p.y));
if (n == 0)
the3dPort->lastError = moveOutVV;
}
void
LineTo3d(vector *x)
/*
Move to and draw a line from the present position to the position
x.
*/
{
vector ls[2];
vcopy(&the3dPort->position, &ls[0]);
vcopy(x, &ls[1]);
Poly3dLine(2, ls);
MoveTo3d(x);
}
void
Poly3dLine(int n, vector x[])
/*
Draw n-1 line segments through the ordered list of points x.
*/
{
IntVector p;
int i = 0;
RGBColor saveColor, rgb;
GetForeColor(&saveColor);
Transform(n, x, eyec);
for (i = 0; i < n-1; i++) {
if (!Line3dClip(&eyec[i], &eyec[i+1], &ceyec[0], &ceyec[1]))
continue;
Projectf(2, ceyec, cfdc);
if (the3dPort->usedepthque) {
rgb2cv(&saveColor, &frgb[0]);
DepthColor(&frgb[0], cfdc[0].z, &cfrgb[0]);
DepthColor(&frgb[0], cfdc[1].z, &cfrgb[1]);
if (the3dPort->onlyqd) {
fvscale(0x08000L, &cfrgb[0], &cfrgb[0]);
fvscale(0x08000L, &cfrgb[1], &cfrgb[1]);
fvadd(&cfrgb[0], &cfrgb[1], &cfrgb[0]);
cv2rgb(&cfrgb[0], &rgb);
RGBForeColor(&rgb);
}
} else {
if (!the3dPort->onlyqd) {
rgb2cv(&saveColor, &cfrgb[0]);
rgb2cv(&saveColor, &cfrgb[1]);
}
}
if (the3dPort->onlyqd) {
fv2iv(&cfdc[0], &p);
MoveTo(p.x, p.y);
fv2iv(&cfdc[1], &p);
LineTo(p.x, p.y);
} else {
C3dLine(&cfdc[0], &cfdc[1], &cfrgb[0], &cfrgb[1]);
}
}
RGBForeColor(&saveColor);
}
void
PolyC3dLine(int n, vector x[], vector c[])
/*
Draw n-1 line segments through the ordered list of points x. Each
line segment will be color blended between the associated colors
in c.
*/
{
IntVector p;
int i = 0;
RGBColor saveColor, rgb;
GetForeColor(&saveColor);
Transform(n, x, eyec);
for (i = 0; i < n-1; i++) {
if (!LineC3dClip(&eyec[i], &eyec[i+1], &ceyec[0], &ceyec[1],
&c[i], &c[i+1], &ccolor[i], &ccolor[i+1]))
continue;
Projectf(2, ceyec, cfdc);
if (the3dPort->usedepthque) {
GetFColor(&ccolor[i], &frgb[0]);
GetFColor(&ccolor[i+1], &frgb[1]);
DepthColor(&frgb[0], cfdc[0].z, &cfrgb[0]);
DepthColor(&frgb[0], cfdc[1].z, &cfrgb[1]);
if (the3dPort->onlyqd) {
fvscale(0x08000L, &cfrgb[0], &cfrgb[0]);
fvscale(0x08000L, &cfrgb[1], &cfrgb[1]);
fvadd(&cfrgb[0], &cfrgb[1], &cfrgb[0]);
cv2rgb(&cfrgb[0], &rgb);
RGBForeColor(&rgb);
}
} else {
if (!the3dPort->onlyqd) {
rgb2cv(&saveColor, &cfrgb[0]);
rgb2cv(&saveColor, &cfrgb[1]);
}
}
if (the3dPort->onlyqd) {
fv2iv(&cfdc[0], &p);
MoveTo(p.x, p.y);
fv2iv(&cfdc[1], &p);
LineTo(p.x, p.y);
} else {
C3dLine(&cfdc[0], &cfdc[1], &cfrgb[0], &cfrgb[1]);
}
}
RGBForeColor(&saveColor);
}
void
Poly3dMark(int n, vector x[], void (*markf)(vector *pos))
/*
Mark the n points in x using the marking function markf.
*/
{
int i;
for (i = 0; i < n; i++) {
(*markf)(&x[i]);
}
}
void
PolyC3dMark(int n, vector x[], void (*markf)(vector *pos), vector c[])
/*
Mark the n points in x using the marking function markf with
the colors indentified in c.
*/
{
int i;
FixedVector frgb;
vector v;
RGBColor saveColor, rgb;
GetForeColor(&saveColor);
for (i = 0; i < n; i++) {
GetFColor(&c[i], &frgb);
cv2rgb(&frgb, &rgb);
RGBForeColor(&rgb);
(*markf)(&x[i]);
}
RGBForeColor(&saveColor);
}
void
Poly3dFrame(int n, vector x[])
/*
Frame the polygon defined by the n vertices in x.
*/
{
int i;
double ax, ay, bx, by;
RGBColor saveColor;
if (n < 3)
return;
Transform(n, x, eyec);
Clip3d(&n, eyec, ceyec);
if (n < 3)
return;
Project(n, ceyec, cndc);
if (the3dPort->cullbacks) {
ax = cndc[1].x - cndc[0].x;
ay = cndc[1].y - cndc[0].y;
bx = cndc[2].x - cndc[1].x;
by = cndc[2].y - cndc[1].y;
if (ax * by - ay * bx > 0.0)
return;
}
ndc2fdc(n, cndc, cfdc);
GetForeColor(&saveColor);
if (the3dPort->usedepthque) {
for (i = 0; i < n; i++) {
rgb2cv(&saveColor, &frgb[i]);
DepthColor(&frgb[i], cfdc[i].z, &cfrgb[i]);
}
if (the3dPort->onlyqd) {
FixedVector t;
FixedVector avgcolor = {0, 0, 0};
double t2 = 1.0/n;
Fixed s;
RGBColor rgb;
extended ext;
#if __option(mc68881)
x96tox80(&t2, &ext);
s = X2Fix(ext);
#else
x96tox80(&t2, &ext);
s = X2Fix(ext);
#endif
for (i = 0; i < n; i++) {
fvscale(s, &cfrgb[i], &t);
fvadd(&t, &avgcolor, &avgcolor);
}
cv2rgb(&avgcolor, &rgb);
RGBForeColor(&rgb);
}
} else {
if (!the3dPort->onlyqd) {
for (i = 0; i < n; i++) {
rgb2cv(&saveColor, &cfrgb[i]);
}
}
}
if (the3dPort->onlyqd) {
PolyForm(n, cfdc);
FramePoly(&polyptr);
} else {
for (i = 0; i < n; i++) {
if (i == n-1)
C3dLine(&cfdc[i], &cfdc[0], &cfrgb[i], &cfrgb[0]);
else
C3dLine(&cfdc[i], &cfdc[i+1], &cfrgb[i], &cfrgb[i+1]);
}
}
RGBForeColor(&saveColor);
}
void
Poly3dFrameErase(int n, vector x[])
/*
Erases the frame of the polygon defined by the n vertices in x.
Note: Presently this doesn't deal properly with the z-buffer.
*/
{
int i;
double ax, ay, bx, by;
RGBColor saveColor, eraseColor;
if (n < 3)
return;
Transform(n, x, eyec);
Clip3d(&n, eyec, ceyec);
if (n < 3)
return;
Project(n, ceyec, cndc);
if (the3dPort->cullbacks) {
ax = cndc[1].x - cndc[0].x;
ay = cndc[1].y - cndc[0].y;
bx = cndc[2].x - cndc[1].x;
by = cndc[2].y - cndc[1].y;
if (ax * by - ay * bx > 0.0)
return;
}
ndc2fdc(n, cndc, cfdc);
GetForeColor(&saveColor);
GetBackColor(&eraseColor);
RGBForeColor(&eraseColor);
if (the3dPort->onlyqd) {
PolyForm(n, cfdc);
FramePoly(&polyptr);
} else {
for (i = 0; i < n; i++) {
rgb2cv(&eraseColor, &cfrgb[0]);
if (i == n-1)
C3dLine(&cfdc[i], &cfdc[0], &cfrgb[0], &cfrgb[0]);
else
C3dLine(&cfdc[i], &cfdc[i+1], &cfrgb[0], &cfrgb[0]);
}
}
RGBForeColor(&saveColor);
}
void
PolyC3dFrame(int n, vector x[], vector c[])
/*
Frame the polygon defined by the n vertices in x. Color blend
the line segments according to the vertex colors in c.
*/
{
int i;
double ax, ay, bx, by;
RGBColor saveColor;
if (n < 3)
return;
Transform(n, x, eyec);
ClipC3d(&n, eyec, ceyec, c, ccolor);
if (n < 3)
return;
Project(n, ceyec, cndc);
if (the3dPort->cullbacks) {
ax = cndc[1].x - cndc[0].x;
ay = cndc[1].y - cndc[0].y;
bx = cndc[2].x - cndc[1].x;
by = cndc[2].y - cndc[1].y;
if (ax * by - ay * bx > 0.0)
return;
}
ndc2fdc(n, cndc, cfdc);
GetForeColor(&saveColor);
LoadFColors(n, ccolor);
if (the3dPort->onlyqd) {
FixedVector t;
FixedVector avgcolor = {0, 0, 0};
double t2 = 1.0/n;
Fixed s;
RGBColor rgb;
extended ext;
#if __option(mc68881)
x96tox80(&t2, &ext);
s = X2Fix(ext);
#else
x96tox80(&t2, &ext);
s = X2Fix(ext);
#endif
for (i = 0; i < n; i++) {
fvscale(s, &cfrgb[i], &t);
fvadd(&t, &avgcolor, &avgcolor);
}
cv2rgb(&avgcolor, &rgb);
RGBForeColor(&rgb);
}
if (the3dPort->onlyqd) {
PolyForm(n, cfdc);
FramePoly(&polyptr);
} else {
for (i = 0; i < n; i++) {
if (i == n-1)
C3dLine(&cfdc[i], &cfdc[0], &cfrgb[i], &cfrgb[0]);
else
C3dLine(&cfdc[i], &cfdc[i+1], &cfrgb[i], &cfrgb[i+1]);
}
}
RGBForeColor(&saveColor);
}
void
Poly3dFill(int n, vector x[])
/*
Fill the polygon defined by the n vertices in x.
*/
{
int i;
double ax, ay, bx, by;
RGBColor saveColor;
if (the3dPort->wireframe) {
Poly3dFrame(n, x);
} else {
if (n < 3)
return;
Transform(n, x, eyec);
Clip3d(&n, eyec, ceyec);
if (n < 3)
return;
Project(n, ceyec, cndc);
if (the3dPort->cullbacks) {
ax = cndc[1].x - cndc[0].x;
ay = cndc[1].y - cndc[0].y;
bx = cndc[2].x - cndc[1].x;
by = cndc[2].y - cndc[1].y;
if (ax * by - ay * bx > 0.0)
return;
}
ndc2fdc(n, cndc, cfdc);
GetForeColor(&saveColor);
if (the3dPort->usedepthque) {
for (i = 0; i < n; i++) {
rgb2cv(&saveColor, &frgb[i]);
DepthColor(&frgb[i], cfdc[i].z, &cfrgb[i]);
}
if (the3dPort->onlyqd) {
FixedVector t;
FixedVector avgcolor = {0, 0, 0};
double t2 = 1.0/n;
Fixed s;
RGBColor rgb;
extended ext;
#if __option(mc68881)
x96tox80(&t2, &ext);
s = X2Fix(ext);
#else
x96tox80(&t2, &ext);
s = X2Fix(ext);
#endif
for (i = 0; i < n; i++) {
fvscale(s, &cfrgb[i], &t);
fvadd(&t, &avgcolor, &avgcolor);
}
cv2rgb(&avgcolor, &rgb);
RGBForeColor(&rgb);
}
} else {
if (!the3dPort->onlyqd) {
for (i = 0; i < n; i++) {
rgb2cv(&saveColor, &cfrgb[i]);
}
}
}
if (the3dPort->onlyqd) {
PolyForm(n, cfdc);
PaintPoly(&polyptr);
} else {
GouraudShade(n, cfdc, cfrgb);
}
RGBForeColor(&saveColor);
}
}
void
Poly3dErase(int n, vector x[])
/*
Erase the polygon defined by the n vertices in x.
Note: Presently this doesn't appropriately deal with the z-buffer.
*/
{
int i;
double ax, ay, bx, by;
RGBColor saveColor, eraseColor;
if (the3dPort->wireframe) {
Poly3dFrameErase(n, x);
} else {
if (n < 3)
return;
Transform(n, x, eyec);
Clip3d(&n, eyec, ceyec);
if (n < 3)
return;
Project(n, ceyec, cndc);
if (the3dPort->cullbacks) {
ax = cndc[1].x - cndc[0].x;
ay = cndc[1].y - cndc[0].y;
bx = cndc[2].x - cndc[1].x;
by = cndc[2].y - cndc[1].y;
if (ax * by - ay * bx > 0.0)
return;
}
ndc2fdc(n, cndc, cfdc);
GetForeColor(&saveColor);
GetBackColor(&eraseColor);
RGBForeColor(&eraseColor);
if (the3dPort->onlyqd) {
PolyForm(n, cfdc);
PaintPoly(&polyptr);
} else {
for (i = 0; i < n; i++) {
rgb2cv(&eraseColor, &cfrgb[i]);
}
GouraudShade(n, cfdc, cfrgb);
}
RGBForeColor(&saveColor);
}
}
void
PolyC3dFill(int n, vector x[], vector c[])
/*
Fill the polygon defined by the n vertices in x. The
resulting polygon will be color filled with a bilinear
interpolation based on the vertex colors in c.
*/
{
int i;
FixedVector avgcolor = {0, 0, 0};
FixedVector t;
RGBColor saveColor, rgb;
double ax, ay, bx, by;
if (the3dPort->wireframe) {
PolyC3dFrame(n, x, c);
} else {
if (n < 3)
return;
Transform(n, x, eyec);
ClipC3d(&n, eyec, ceyec, c, ccolor);
if (n < 3)
return;
Project(n, ceyec, cndc);
if (the3dPort->cullbacks) {
ax = cndc[1].x - cndc[0].x;
ay = cndc[1].y - cndc[0].y;
bx = cndc[2].x - cndc[1].x;
by = cndc[2].y - cndc[1].y;
if (ax * by - ay * bx > 0.0)
return;
}
ndc2fdc(n, cndc, cfdc);
LoadFColors(n, ccolor);
GetForeColor(&saveColor);
if (the3dPort->onlyqd) {
double t2 = 1.0/n;
Fixed s;
extended ext;
#if __option(mc68881)
x96tox80(&t2, &ext);
s = X2Fix(ext);
#else
x96tox80(&t2, &ext);
s = X2Fix(ext);
#endif
for (i = 0; i < n; i++) {
fvscale(s, &cfrgb[i], &t);
fvadd(&t, &avgcolor, &avgcolor);
}
cv2rgb(&avgcolor, &rgb);
RGBForeColor(&rgb);
PolyForm(n, cfdc);
PaintPoly(&polyptr);
} else {
GouraudShade(n, cfdc, cfrgb);
}
RGBForeColor(&saveColor);
}
}
/* ============================================================ */
/* Some default marking functions: */
void
MarkPoint(vector *pos)
/*
This marks the world coordinate pos with a single pixel of the
current foreground color.
If the point is outside the view volume, the point is not marked.
*/
{
FixedVector x;
IntVector ix;
RGBColor color;
int i = 1;
TranClipProjf(&i, pos, &x);
if (!i)
return;
fv2iv(&x, &ix);
GetForeColor(&color);
SetCPixel(ix.x, ix.y, &color);
}
void
MarkSelectedPoint(vector *pos)
/*
This marks the world coordinate pos with an "x" of the
current foreground color.
The size of the mark is twice that defined by SLTNWDTH.
If the point is outside the view volume, the point is not marked.
*/
{
FixedVector x;
IntVector ix;
int i = 1;
TranClipProjf(&i, pos, &x);
if (!i)
return;
fv2iv(&x, &ix);
MoveTo(ix.x - SLTNWDTH, ix.y);
LineTo(ix.x + SLTNWDTH, ix.y);
MoveTo(ix.x, ix.y - SLTNWDTH);
LineTo(ix.x, ix.y + SLTNWDTH);
}
void
MarkCtrlPoint(vector *pos)
/*
This marks the world coordinate pos with a square of the
current foreground color.
The size of the mark is twice that defined by CNTRLWDTH.
If the point is outside the view volume, the point is not marked.
*/
{
Rect r;
FixedVector x;
IntVector ix;
int i = 1;
TranClipProjf(&i, pos, &x);
if (!i)
return;
fv2iv(&x, &ix);
r.left = r.right = ix.x;
r.top = r.bottom = ix.y;
r.top -= CNTRLWDTH;
r.left -= CNTRLWDTH;
r.right += CNTRLWDTH;
r.bottom += CNTRLWDTH;
PaintRect(&r);
}